;================================================================
;  graph.s
;               A test module with HRG
;
;================================================================
;
; 25thanni, a demo dedicated to the 25th anniversary of the ZX81.
;
; (c)2006 Bodo Wenzel
;
; This program is free software; you can redistribute it and/or
; modify it under the terms of the GNU General Public License as
; published by the Free Software Foundation; either version 2 of
; the License, or (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public
; License along with this program; if not, write to the Free
; Software Foundation Inc., 59 Temple Place, Suite 330, Boston,
; MA 02111-1307 USA
;================================================================

	.module	graph

;	part:			nr:	picture:
;	random			0	random pixels
;	sine			1	sine wave
;	cosine			2	cosine wave
;	product			3	right half square curve
;	arccos			4	curve in lower half
;	arcsin			5	in upper and lower quart
;	arccos(cosine)		6	00,00 -> 80,80 -> FF,FF
;	cosine(arccos)		7	00,00 -> FF,FF
;	arcsin(sine)		8	00,00 -> 40,40 -> 7F,00
;					80,FF -> C0,C0 -> FF,FF
;	sine(arcsin)		9	00,00 -> FF,FF
;	quotient		10	hyperbel through 40,80
;	quotient(product)	11	00,00 -> B5,B5, hyperbel
;	product(quotient)	12	00,00 -> 7F,FF -> FF,FF
;	x >= y			13
TEST	=	1	<<	13

;= Externals ====================================================

	.globl	NXTLIN
	.globl	H_FILE

	.globl	set_show
	.globl	show_dummy
	.globl	vsync
	.globl	empty_scroll

	.globl	HRG_WIDTH,HRG_HEIGHT
	.globl	show_hrg
	.globl	h_reset

	.if	TEST&(1<<0)
	.globl	random
	.endif
	.if	TEST&((1<<1)|(1<<8)|(1<<9))
	.globl	MATH_SIGN
	.globl	sine
	.endif
	.if	TEST&((1<<2)|(1<<6)|(1<<7))
	.globl	MATH_SIGN
	.globl	cosine
	.endif
	.if	TEST&((1<<3)|(1<<11)|(1<<12))
	.globl	product
	.endif
	.if	TEST&((1<<4)|(1<<6)|(1<<7))
	.globl	MATH_SIGN
	.globl	arccos
	.endif
	.if	TEST&((1<<5)|(1<<8)|(1<<9))
	.globl	MATH_SIGN
	.globl	arcsin
	.endif
	.if	TEST&((1<<10)|(1<<11)|(1<<12))
	.globl	quotient
	.endif

;= Constants ====================================================

; double global definition checked by linker
HRG_WIDTH	==	256
HRG_HEIGHT	==	192

BITS_PER_BYTE	=	8
BYTES_PER_WORD	=	2

PIC_WIDTH	=	256	; function input range
PIC_HEIGHT	=	256	; function output range
BYTE_WIDTH	=	PIC_WIDTH/BITS_PER_BYTE

PAUSE		=	50

	.if	HRG_WIDTH-PIC_WIDTH
	.error	"HRG width error"
	.endif

;= Program code =================================================

	.area	_CODE

;- Show a HRG screen --------------------------------------------

graph::
	ld	hl,#empty_scroll
	ld	(show_dummy),hl
	ld	hl,#show_dummy
	call	set_show

	ld	de,(NXTLIN)
	ld	hl,#PIC_HEIGHT*BYTE_WIDTH
	add	hl,de
	ld	(H_FILE),hl

	ld	b,#PIC_HEIGHT
	ld	c,#BYTE_WIDTH
g_stk_lp:
	ld	(hl),e
	inc	hl
	ld	(hl),d
	inc	hl
	ld	a,e
	add	a,c
	ld	e,a
	jr	nc,g_stk_nx
	inc	d
g_stk_nx:
	djnz	g_stk_lp

	call	h_reset

	ld	hl,#empty_scroll
	ld	(show_hrg),hl
	ld	hl,#show_hrg
	call	set_show

	ld	hl,(NXTLIN)
	ld	e,l
	ld	d,h
	ld	(hl),#0
	inc	de
	ld	bc,#PIC_HEIGHT*BYTE_WIDTH-1
	ldir

	ld	hl,(NXTLIN)
	ld	de,#BYTE_WIDTH/4-1
	ld	bc,#PIC_HEIGHT*4
g_y_lp:
	ld	(hl),#0x80
	add	hl,de
	ld	(hl),#0x01
	inc	hl
	dec	bc
	ld	a,c
	or	b
	jr	nz,g_y_lp

	ld	hl,(NXTLIN)
	ld	de,#(PIC_HEIGHT/4-2)*BYTE_WIDTH
	ld	c,#4
g_x_lp1:
	ld	b,#BYTE_WIDTH
g_x_lp2:
	ld	(hl),#0xFF
	inc	hl
	djnz	g_x_lp2
	add	hl,de
	ld	b,#BYTE_WIDTH
g_x_lp3:
	ld	(hl),#0xFF
	inc	hl
	djnz	g_x_lp3
	dec	c
	jr	nz,g_x_lp1

	ld	b,#PIC_WIDTH
g_f_lp:
	push	bc
	dec	b
	ld	a,b
	.if	TEST&(1<<0)
	call	random
	.endif
	.if	TEST&(1<<1)
	call	sine
	xor	#MATH_SIGN
	.endif
	.if	TEST&(1<<2)
	call	cosine
	xor	#MATH_SIGN
	.endif
	.if	TEST&(1<<3)
	ld	e,a
	call	product
	.endif
	.if	TEST&(1<<4)
	xor	#MATH_SIGN
	call	arccos
	.endif
	.if	TEST&(1<<5)
	xor	#MATH_SIGN
	call	arcsin
	.endif
	.if	TEST&(1<<6)
	call	cosine
	call	arccos
	.endif
	.if	TEST&(1<<7)
	call	arccos
	call	cosine
	.endif
	.if	TEST&(1<<8)
	call	sine
	call	arcsin
	.endif
	.if	TEST&(1<<9)
	call	arcsin
	call	sine
	.endif
	.if	TEST&(1<<10)
	ld	e,a
	ld	a,#0x40		; dividend 0.5
	call	quotient
	.endif
	.if	TEST&(1<<11)
	ld	e,a
	call	product
	ld	e,b
	call	quotient
	.endif
	.if	TEST&(1<<12)
	ld	e,a
	ld	a,#0xFF		; dividend 0.99
	call	quotient
	ld	e,b
	call	product
	.endif
	.if	TEST&(1<<13)
	ld	a,b
	xor	#0x80
	ld	b,a
	and	#7
	rrca
	rrca
	rrca
	xor	#0x80
	cp	b
	jr	nc,g_f_noplot
	.endif
	cpl
	ld	c,a
	call	plot
g_f_noplot:
	pop	bc
	djnz	g_f_lp

;-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

g_loop:
	ld	b,#PAUSE
g_p1_lp:
	call	vsync
	djnz	g_p1_lp

	ld	de,#BYTES_PER_WORD
	ld	b,#PIC_HEIGHT-HRG_HEIGHT
g_down_lp:
	call	vsync
	ld	hl,(H_FILE)
	add	hl,de
	ld	(H_FILE),hl
	djnz	g_down_lp

	ld	b,#PAUSE
g_p2_lp:
	call	vsync
	djnz	g_p2_lp

	ld	de,#-BYTES_PER_WORD
	ld	b,#PIC_HEIGHT-HRG_HEIGHT
g_up_lp:
	call	vsync
	ld	hl,(H_FILE)
	add	hl,de
	ld	(H_FILE),hl
	djnz	g_up_lp

	jr	g_loop		; returns never

;- Plot a pixel -------------------------------------------------
; B	x coordinate
; C	y coordinate

plot:
	ld	hl,(NXTLIN)	; base pointer

	ld	e,c
	ld	d,#0
	ld	a,#BYTE_WIDTH
p_ylp:
	add	hl,de
	dec	a
	jr	nz,p_ylp	; add y offset

	ld	a,b
	rrca
	rrca
	rrca
	and	#0x1F
	ld	e,a
	add	hl,de		; add x offset

	ld	e,#0x01
	ld	a,b
	and	#0x07
	inc	a
p_xlp:
	rrc	e
	dec	a
	jr	nz,p_xlp	; build pixel mask

	ld	a,(hl)
	xor	e
	ld	(hl),a		; set pixel

	ret

;= Heap usage ===================================================

;		bitmap
HEAP =		PIC_HEIGHT*BYTE_WIDTH
;		pointer table for H_FILE
HEAP =	HEAP +	PIC_HEIGHT*BYTES_PER_WORD

	.area	_HEAP	(ABS,OVR)
	.ds	HEAP

;= The end ======================================================
